using System;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;

public class GetProjectMacro
{
  private static readonly UeProjMacroDate ct = new(
    "Source",
    ["Intermediate", "Build", "Win64", "x64", "UnrealEditor", "Development"],
    "DLLEXPORT",
    "Definitions.",
    "Public",
    "#define",
    new Regex(@"\bclass\b", RegexOptions.None)
  );

  public static string Exec(UeProjPojo proj_info)
  {
    string res = null;
    // 优先从definitions.h中找
    res = FindMacroFromDefinitionsFile(proj_info);
    if (!string.IsNullOrEmpty(res)) return res;

    // 找Public中的.h文件
    res = FindMacroFromSource(proj_info.projectSourcePublicPath);
    if (!string.IsNullOrEmpty(res)) return res;

    // 只有Source的情况
    if (proj_info.projectName.Equals(ct.Source))
    {
      res = FindMacroFromSource(proj_info.sourcePublicPath);
    }
    // 不是Source的情况，且是newprojp
    else if (proj_info.param.IsNewProjP())
    {
      // 为newprojp生成宏
      res = CreatMacro(proj_info);
    }

    // 没找到就报错
    if (string.IsNullOrEmpty(res))
      throw new UePTException(Error.Err_3);

    return res;
  }

  private static string FindMacroFromDefinitionsFile(UeProjPojo proj_info)
  {
    try
    {
      string definitions_file = Get_definitions_file(proj_info);

      // 优先从definitions.h中找
      if (!File.Exists(definitions_file)) return null;

      string[] lines = File.ReadAllLines(definitions_file);
      string define_macro = lines
        .Select(str => str.Trim())
        .FirstOrDefault(str => str.EndsWith(ct.DLLEXPORT));
      string macro_str = define_macro
        .Split(" ")
        .FirstOrDefault(str => !string.IsNullOrWhiteSpace(str) && !str.Equals(ct.Define));

      return macro_str;

    }
    catch (Exception)
    {
      return null;
    }
  }

  private static string FindMacroFromSource(string source_path)
  {
    try
    {
      if (!Directory.Exists(source_path)) return null;
      // 仅找两个文件
      string[] files = Directory.GetFiles(source_path, "*.h", SearchOption.AllDirectories);
      // files.ToList().ForEach(Console.WriteLine);

      string macro_str = null;
      foreach (string file in files)
      {
        string macro_str_2 = GetMacroFromDotH(file);

        if (!string.IsNullOrEmpty(macro_str) && macro_str.Equals(macro_str_2)) break;

        macro_str = macro_str_2;
      }

      return macro_str;
    }
    catch (Exception)
    {
      return null;
    }

  }

  private static string GetMacroFromDotH(string path)
  {

    string[] lines = File.ReadAllLines(path);
    foreach (string line in lines)
    {
      string str = line.Trim();

      if (str.StartsWith("class") && ct.regex1.IsMatch(str) && !str.EndsWith(";"))
      {
        return str.Split(" ").Where(s => !string.IsNullOrWhiteSpace(s))
        .FirstOrDefault(str => !str.Equals("class"));
      }
    }
    return null;
  }

  private static string Get_definitions_file(UeProjPojo proj_info)
  {
    return Path.Combine(
      proj_info.rootPath,
      Path.Combine(ct.Intermediate),
      proj_info.projectName,
      ct.Definitions + proj_info.projectName + ".h"
    );
  }

  private static string CreatMacro(UeProjPojo proj_info)
  {
    string macro_str = proj_info.projectName.ToUpper();

    return macro_str + "_API";
  }

}

// Intermediate\Build\Win64\x64\UnrealEditor\Development\
public record UeProjMacroDate(
  string Source,
  string[] Intermediate,
  string DLLEXPORT,
  string Definitions,
  string Public,
  string Define,
  Regex regex1
)
{ }
